﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.PhantomJS;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.UI;
namespace CrawlerPicModel
{
    public class StrongCrawler : ICrawler
    {
        public event EventHandler<OnStartEventArgs> OnStart;//爬虫开始
        public event EventHandler<OnCompletedEventArgs> OnCompleted;//爬虫完成
        public event EventHandler<OnErrorEventArgs> OnError;
        private PhantomJSOptions Options;//定义phantomJS内核参数
        private PhantomJSDriverService DriverService;//定义selenium驱动配置
        public StrongCrawler(string proxy = null)
        {
            Options = new PhantomJSOptions();
            DriverService = PhantomJSDriverService.CreateDefaultService(Environment.CurrentDirectory);//初始化selenium配置，传入存放phantJs文件目录
            DriverService.IgnoreSslErrors = true;//忽略证书错误
            DriverService.WebSecurity = false;//禁用网络安全
            DriverService.HideCommandPromptWindow = true;//隐藏弹出窗口
            DriverService.LoadImages = false;//禁止加载图片
            DriverService.LocalToRemoteUrlAccess = true;//允许使用本地资源响应远程url
            Options.AddAdditionalCapability(@"phantomjs.page.settings.userAgent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");
            if (proxy != null)
            {
                DriverService.ProxyType = "HTTP";//使用http代理
                DriverService.Proxy = proxy;//代理IP及端口
            }
            else
            {
                DriverService.ProxyType = "none";//不实用代理

            }
           

        }
       
      
        public async Task Start(Uri uri, Script script, Operation operation)
        {
            await Task.Run(() =>
            {
                if (OnStart != null) OnStart(this, new OnStartEventArgs(uri));
                var driver = new PhantomJSDriver(DriverService, Options);//实例化phantomjs的webDriver
                try
                {
                    var watch = DateTime.Now;
                    driver.Navigate().GoToUrl(uri.ToString());//请求url地址
                    if (script != null) driver.ExecuteScript(script.Code, script.Args);//执行js代码
                    if (operation.Action != null) operation.Action.Invoke(driver);
                    var driverWait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(operation.Timeout));//设置超时时间为x毫秒
                    if (operation.Condition != null) driverWait.Until(operation.Condition);
                    var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;//获取当前任务线程ID
                    var milliseconds = DateTime.Now.Subtract(watch).Milliseconds;//获取请求执行时间;
                    var pageSource = driver.PageSource;//获取网页Dom结构
                    this.OnCompleted?.Invoke(this, new OnCompletedEventArgs(uri, threadId, milliseconds, pageSource, driver));
                }
                catch (Exception ex)
                {
                    this.OnError?.Invoke(this, new OnErrorEventArgs(uri, ex));
                }
                finally
                {
                    driver.Close();
                    driver.Quit();
                }
            });
        }
    }
    

    /// <summary>
    /// 爬虫完成
    /// </summary>
    public class OnCompletedEventArgs
    {
        public Uri Uri { get; private set; }// 爬虫URL地址
        public int ThreadId { get; private set; }// 任务线程ID
        public string PageSource { get; private set; }// 页面源代码
        public IWebDriver WebDriver { get; private set; }
        public long Milliseconds { get; private set; }// 爬虫请求执行事件
        public OnCompletedEventArgs(Uri uri, int threadId, long milliseconds, string pageSource, IWebDriver driver)
        {
            this.Uri = uri;
            this.ThreadId = threadId;
            this.Milliseconds = milliseconds;
            this.PageSource = pageSource;
            this.WebDriver = driver;
        }
    }


    public class Script
    {
        public string Code { get; set; }
        public  object[] Args { get; set; }
    }
    public class Operation
    {
        public int Timeout { get; set; }

        public Action<IWebDriver> Action { get; set; }

        public Func<IWebDriver, bool> Condition { get; set; }

    }
    /// <summary>
    /// 爬虫异常
    /// </summary>
    public class OnErrorEventArgs
    {
        public Uri Uri { get; set; }
        public Exception Exception { get; set; }
        public OnErrorEventArgs(Uri uri, Exception exception)
        {
            Uri = uri;
            Exception = exception;
        }
    }
    /// <summary>
    /// 爬虫开始
    /// </summary>
    public class OnStartEventArgs
    {
        public Uri Uri { get; set; }
        public OnStartEventArgs(Uri uri)
        {
            Uri = uri;
        }
    }
    public interface ICrawler
    {
        event EventHandler<OnStartEventArgs> OnStart;
        event EventHandler<OnCompletedEventArgs> OnCompleted;
        event EventHandler<OnErrorEventArgs> OnError;
        Task Start(Uri uri, Script script, Operation operation);//异步
    }
}
